//! 简化的被动扫描引擎

use anyhow::Result;
use chrono::{DateTime, Utc};
use http::{Method, Uri};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use thiserror::Error;
use tokio::sync::RwLock;
use tracing::{debug, error, info, warn};

#[derive(Error, Debug)]
pub enum ScanError {
    #[error("Event processing error: {0}")]
    EventError(String),
    #[error("Storage error: {0}")]
    StorageError(String),
    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),
    #[error("Serialization error: {0}")]
    SerializationError(#[from] serde_json::Error),
}

/// HTTP事件
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HttpEvent {
    /// 事件ID
    pub id: String,
    /// 事件时间
    pub timestamp: DateTime<Utc>,
    /// 请求方法
    pub method: String,
    /// 请求URL
    pub url: String,
    /// 状态码
    pub status_code: Option<u16>,
    /// 响应头
    pub headers: HashMap<String, String>,
    /// 响应体内容
    pub body: String,
    /// 来源IP
    pub source_ip: String,
}

impl HttpEvent {
    pub fn new_request(
        method: Method,
        uri: Uri,
        headers: HashMap<String, String>,
        body: String,
        source_ip: String,
    ) -> Self {
        Self {
            id: uuid::Uuid::new_v4().to_string(),
            timestamp: Utc::now(),
            method: method.to_string(),
            url: uri.to_string(),
            status_code: None,
            headers,
            body,
            source_ip,
        }
    }

    pub fn new_response(
        status_code: u16,
        headers: HashMap<String, String>,
        body: String,
        request_url: String,
        method: String,
    ) -> Self {
        Self {
            id: uuid::Uuid::new_v4().to_string(),
            timestamp: Utc::now(),
            method,
            url: request_url,
            status_code: Some(status_code),
            headers,
            body,
            source_ip: "server".to_string(),
        }
    }

    /// 获取去重键
    pub fn get_dedup_key(&self) -> String {
        format!("{}:{}:{}", self.url, self.method, self.status_code.unwrap_or(0))
    }

    /// 计算body哈希
    pub fn get_body_hash(&self) -> String {
        use sha2::{Digest, Sha256};
        let mut hasher = Sha256::new();
        hasher.update(self.body.as_bytes());
        format!("{:x}", hasher.finalize())
    }
}

/// 扫描结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScanResult {
    pub id: String,
    pub rule_name: String,
    pub severity: Severity,
    pub title: String,
    pub description: String,
    pub url: String,
    pub evidence: String,
    pub timestamp: DateTime<Utc>,
    pub confidence: u8,
}

/// 严重程度
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum Severity {
    Info,
    Low,
    Medium,
    High,
    Critical,
}

impl std::fmt::Display for Severity {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Severity::Info => write!(f, "Info"),
            Severity::Low => write!(f, "Low"),
            Severity::Medium => write!(f, "Medium"),
            Severity::High => write!(f, "High"),
            Severity::Critical => write!(f, "Critical"),
        }
    }
}

/// 扫描规则
#[derive(Debug, Clone)]
pub struct ScanRule {
    pub name: String,
    pub pattern: Regex,
    pub severity: Severity,
    pub title: String,
    pub description: String,
}

impl ScanRule {
    pub fn new(
        name: String,
        pattern: &str,
        severity: Severity,
        title: String,
        description: String,
    ) -> Result<Self> {
        Ok(Self {
            name,
            pattern: Regex::new(pattern)?,
            severity,
            title,
            description,
        })
    }

    pub fn match_event(&self, event: &HttpEvent) -> Option<ScanResult> {
        if let Some(mat) = self.pattern.find(&event.body) {
            Some(ScanResult {
                id: uuid::Uuid::new_v4().to_string(),
                rule_name: self.name.clone(),
                severity: self.severity.clone(),
                title: self.title.clone(),
                description: self.description.clone(),
                url: event.url.clone(),
                evidence: format!("Matched at position {}..{}: {}",
                    mat.start(), mat.end(), mat.as_str()),
                timestamp: Utc::now(),
                confidence: 80,
            })
        } else {
            None
        }
    }
}

/// 简化的被动扫描引擎
pub struct PassiveScanEngine {
    rules: Arc<RwLock<Vec<ScanRule>>>,
    results: Arc<RwLock<Vec<ScanResult>>>,
    seen_events: Arc<RwLock<std::collections::HashSet<String>>>,
}

impl PassiveScanEngine {
    pub fn new() -> Self {
        Self {
            rules: Arc::new(RwLock::new(Vec::new())),
            results: Arc::new(RwLock::new(Vec::new())),
            seen_events: Arc::new(RwLock::new(std::collections::HashSet::new())),
        }
    }

    /// 创建并初始化引擎
    pub async fn new_initialized() -> Self {
        let engine = Self::new();
        engine.load_default_rules().await.unwrap_or_else(|e| {
            eprintln!("Failed to load default rules: {}", e);
        });
        engine
    }

    /// 加载默认规则
    async fn load_default_rules(&self) -> Result<()> {
        let default_rules = vec![
            // 密码泄露检测
            ScanRule::new(
                "password_exposure".to_string(),
                "(?i)\"password\"\\s*:\\s*\"([^\"]{4,})\"",
                Severity::High,
                "Password Disclosure".to_string(),
                "Potential password disclosure in response".to_string(),
            )?,

            // API密钥泄露
            ScanRule::new(
                "api_key_exposure".to_string(),
                "(?i)(api[_-]?key|apikey)\\s*[:=]\\s*['\\\"]?[a-zA-Z0-9]{16,}",
                Severity::High,
                "API Key Exposure".to_string(),
                "API key exposure detected".to_string(),
            )?,

            // SQL错误
            ScanRule::new(
                "sql_error".to_string(),
                "(?i)(sql\\s+syntax|mysql_fetch|ORA-\\d+|Microsoft\\s+ODBC\\s+SQL)",
                Severity::Medium,
                "SQL Error".to_string(),
                "SQL error message detected".to_string(),
            )?,

            // 目录列表
            ScanRule::new(
                "directory_listing".to_string(),
                "(?i)(<title>Index of|Directory Listing for|<pre><a href=)",
                Severity::Low,
                "Directory Listing".to_string(),
                "Directory listing enabled".to_string(),
            )?,
        ];

        let mut rules_guard = self.rules.write().await;
        *rules_guard = default_rules;
        info!("Loaded {} default scan rules", rules_guard.len());
        Ok(())
    }

    /// 处理HTTP事件
    pub async fn process_event(&self, event: HttpEvent) -> Result<Vec<ScanResult>> {
        // 检查去重
        let dedup_key = event.get_dedup_key();
        {
            let mut seen = self.seen_events.write().await;
            if seen.contains(&dedup_key) {
                debug!("Event already processed: {}", dedup_key);
                return Ok(Vec::new());
            }
            seen.insert(dedup_key);
        }

        debug!("Processing HTTP event: {} {}", event.method, event.url);

        let rules = self.rules.read().await;
        let mut results = Vec::new();

        for rule in rules.iter() {
            if let Some(result) = rule.match_event(&event) {
                warn!("Security issue detected: {} - {}", result.title, result.url);
                results.push(result);
            }
        }

        // 保存结果
        if !results.is_empty() {
            let mut results_guard = self.results.write().await;
            results_guard.extend(results.clone());
        }

        Ok(results)
    }

    /// 获取所有结果
    pub async fn get_results(&self) -> Vec<ScanResult> {
        self.results.read().await.clone()
    }

    /// 获取结果统计
    pub async fn get_stats(&self) -> ScanStats {
        let results = self.results.read().await;
        let total = results.len();
        let mut by_severity = HashMap::new();

        for result in results.iter() {
            *by_severity.entry(result.severity.clone()).or_insert(0) += 1;
        }

        ScanStats {
            total_results: total,
            results_by_severity: by_severity,
        }
    }

    /// 添加自定义规则
    pub async fn add_rule(&self, rule: ScanRule) -> Result<()> {
        let mut rules = self.rules.write().await;
        rules.push(rule);
        Ok(())
    }

    /// 清除结果
    pub async fn clear_results(&self) {
        let mut results = self.results.write().await;
        results.clear();
        let mut seen = self.seen_events.write().await;
        seen.clear();
    }
}

impl Default for PassiveScanEngine {
    fn default() -> Self {
        Self::new()
    }
}

/// 扫描统计
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScanStats {
    pub total_results: usize,
    pub results_by_severity: HashMap<Severity, usize>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;

    #[tokio::test]
    async fn test_password_detection() {
        let engine = PassiveScanEngine::new_initialized().await;

        let mut headers = HashMap::new();
        headers.insert("content-type".to_string(), "application/json".to_string());

        let event = HttpEvent::new_response(
            200,
            headers,
            r#"{"user": "admin", "password": "secret123"}"#.to_string(),
            "https://example.com/api/users".to_string(),
            "POST".to_string(),
        );

        let results = engine.process_event(event).await.unwrap();
        assert_eq!(results.len(), 1);
        assert_eq!(results[0].rule_name, "password_exposure");
        assert_eq!(results[0].severity, Severity::High);
    }

    #[tokio::test]
    async fn test_deduplication() {
        let engine = PassiveScanEngine::new_initialized().await;

        let mut headers = HashMap::new();
        headers.insert("content-type".to_string(), "application/json".to_string());

        let event = HttpEvent::new_response(
            200,
            headers,
            r#"{"user": "admin", "password": "secret123"}"#.to_string(),
            "https://example.com/api/users".to_string(),
            "POST".to_string(),
        );

        // 第一次处理
        let results1 = engine.process_event(event.clone()).await.unwrap();
        assert_eq!(results1.len(), 1);

        // 第二次处理相同事件（应该被去重）
        let results2 = engine.process_event(event).await.unwrap();
        assert_eq!(results2.len(), 0);
    }
}